<template>
    <div class="form-item-box">
        <div
            class="form-item-wrap"
            v-for="(item, index) in formListCopy"
            :key="index"
            :style="{ width: item.width || '100%' }"
        >
            <div class="form-item-label" :style="{ width: widthLabel + 'px' }">
                <span class="star" v-if="item.isNeed !== false">*</span>{{ item.label }}
            </div>
            <div class="form-item-component" :class="{ 'error-status': errorObj[item.id] }">
                <div class="error-label">{{ item.currentErrorLabel }}</div>
                <component :is="getComponent(item.type)" v-model="item.value" :info="item" @change="changeHandle" />
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup name="SGFormItem">
import type { IComponentInfoType } from '@/types/component';
import type { PropType } from 'vue';
import { getComponent } from '../map';
import { cloneDeep } from 'lodash';
import { validatenull, isvalidPhone, isvalidEmail, isvalidIdCard } from '@/utils/validate';
const { formList } = defineProps({
    value: {
        type: Object,
        default: () => {}
    },
    formList: {
        type: Array as PropType<IComponentInfoType[]>,
        default: () => []
    }
});

const emit = defineEmits(['update:value']);
let formListCopy = ref(cloneDeep(formList));
let errorObj: Record<string, boolean> = reactive({});
let widthLabel = ref(72);

// 获取label最长宽度
const getLabelWidth = () => {
    const textList = formListCopy.value.filter((item) => item.type != 'slot');
    if (!textList.length) return;
    const maxTextLength = textList.reduce((maxLength, obj) => {
        return Math.max(maxLength, obj.label.length);
    }, 0);
    const isNoStar = textList.every((obj) => obj.isNeed === false);
    if (maxTextLength >= 8) {
        widthLabel.value = 8 * 14 + 16;
    } else {
        widthLabel.value = maxTextLength * 14 + 16;
    }
    if (!isNoStar) widthLabel.value += 8;
};
// 表单项改变
const changeHandle = (val: IComponentInfoType) => {
    validateItemHandle(val);
};
//初始化表单内容
const initHandle = () => {
    // 初始化必填状态errorObj
    formListCopy.value.forEach((item: IComponentInfoType) => {
        item.currentErrorLabel = '';
        errorObj[item.id] = false;
    });
    // 初始化label宽度
    getLabelWidth();
};
// 返回值
const returnValue = () => {
    const data: Record<string, any> = {};
    formListCopy.value.forEach((item: IComponentInfoType) => {
        if (item.type != 'slot') {
            data[item.id] = item.value;
        }
    });
    emit('update:value', data);
};
// 校验表单项
const validateItemHandle = (obj: { id: string; value: any; isNeed?: boolean }) => {
    // 1.查找对应项
    const targetItem = formListCopy.value.find((item) => item.id === obj.id);
    if (!targetItem) return;

    const { id, label, verType, verRule } = targetItem;
    const isEmpty = validatenull(obj.value);

    // 2. 非必填且值为空时直接返回
    if (obj.isNeed === false && isEmpty) {
        setValidationResult(id, '', false);
        return;
    }

    // 3. 处理空值情况
    if (isEmpty) {
        setValidationResult(id, `${label}不能为空`, true);
        return;
    }

    // 4. 处理区间类型输入
    if (targetItem.type === 'interval') {
        handleIntervalValidation(targetItem, obj.value);
        return;
    }

    // 5. 处理内置校验规则
    if (verType) {
        handleBuiltInValidation(targetItem);
        return;
    }

    // 6. 处理自定义校验规则
    if (typeof verRule === 'function') {
        handleCustomValidation(targetItem);
        return;
    }

    // 7. 默认情况
    setValidationResult(id, '', false);
};

// 设置校验结果
const setValidationResult = (id: string, errorMsg: string, isError: boolean) => {
    const targetItem = formListCopy.value.find((item) => item.id === id);
    if (targetItem) {
        targetItem.currentErrorLabel = errorMsg;
        errorObj[id] = isError;
    }
};

// 处理区间组件校验
const handleIntervalValidation = (item: IComponentInfoType, value: [any, any]) => {
    const [start, end] = value;

    if (start === '') {
        setValidationResult(item.id, item.minErrorLabel || `请输入正确的${item.label}起始值`, true);
    } else if (end === '') {
        setValidationResult(item.id, item.maxErrorLabel || `请输入正确的${item.label}结束值`, true);
    }
};

// 处理内置校验规则
const handleBuiltInValidation = (item: IComponentInfoType) => {
    let isValid = false;

    switch (item.verType) {
        case 'phone':
            isValid = isvalidPhone(item.value);
            break;
        case 'email':
            isValid = isvalidEmail(item.value);
            break;
        case 'idCard':
            isValid = isvalidIdCard(item.value);
            break;
    }

    setValidationResult(item.id, isValid ? '' : `请输入正确的${item.label}`, !isValid);
};

// 处理自定义校验规则
const handleCustomValidation = (item: IComponentInfoType) => {
    const isValid = item.verRule?.(item.value) ?? false;

    setValidationResult(item.id, isValid ? '' : item.verErrorLabel || `请输入正确的${item.label}`, !isValid);
};

// 校验表单
const validateFormHandle = () => {
    formListCopy.value.forEach((item: IComponentInfoType) => {
        validateItemHandle(item);
    });
    const isError = Object.values(errorObj).some((item) => item);
    if (!isError) returnValue();
    return !isError;
};
// 暴露方法给父组件
defineExpose({
    validateFormHandle,
    returnValue
});
onBeforeMount(() => {
    initHandle();
});
</script>
